package com.ebraga.trackerclub.android.dao.core;

import java.util.ArrayList;
import java.util.List;

import android.database.Cursor;

import com.ebraga.trackerclub.android.dao.api.RankingDao;
import com.ebraga.trackerclub.android.dao.entity.RankingAndroid;
import com.ebraga.trackerclub.android.exception.BackofficeDBConnectionException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeDaoException;
import com.ebraga.trackerclub.android.exception.dao.BackofficeIllegalArgumentDaoException;
import com.ebraga.trackerclub.android.util.ISmartServiceConstants;
import com.ebraga.trackerclub.android.util.api.AndroidContentValues;
import com.ebraga.trackerclub.android.util.api.DataAccessObject;

public abstract class RankingDaoImpl implements RankingDao {
	 
	private DataAccessObject dataAccessObject;
	private AndroidContentValues contentValues;
	
	public RankingDaoImpl (DataAccessObject dataAccessObject){
		this.dataAccessObject = dataAccessObject;
	}
	
	public void setContentValues(AndroidContentValues contentValues) {
		this.contentValues = contentValues;
	}
	
	private static final String[] SELECTED_FIELDS = new String[] {
			ISmartServiceConstants.DATABASE.RANKING.FIELD_ID,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_NAME,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_BRAND,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_MODEL,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_LATITUDE,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_LONGITUDE,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_DATE,
			ISmartServiceConstants.DATABASE.RANKING.FIELD_SPEED
			};
	
	@Override
	public void insert(RankingAndroid rankingAndroid)
			throws BackofficeDBConnectionException, BackofficeDaoException {		
		Long ok;
		
		if (rankingAndroid == null){
			throw new BackofficeDaoException("Posição inválida");
		}
		try {
			dataAccessObject.getDB();
		} catch (BackofficeDaoException e) {
			throw new BackofficeDBConnectionException("Erro ao conectar banco de dados", e);
		}
		try {
			validateEntityToPersist(rankingAndroid);
			ok = dataAccessObject.getDB().insert(ISmartServiceConstants.DATABASE.RANKING.TABLE_NAME, createRecord(rankingAndroid));
			if (ok > 0) {
				rankingAndroid.setXidRanking(ok);
			}
		} catch (BackofficeDBConnectionException e) {
			throw new BackofficeDBConnectionException("Erro ao conectar banco de dados", e);
		} catch (Exception e) {
			throw new BackofficeDaoException("Erro ao inserir posição", e);
		}
	}

	@Override
	public List<RankingAndroid> retrieveRanking()
			throws BackofficeDBConnectionException, BackofficeDaoException {
		
		try {
			dataAccessObject.getDB();
		} catch (BackofficeDaoException e) {
			throw new BackofficeDBConnectionException("Erro ao conectar banco de dados");
		}
		
		Cursor cursor = null;
		String orderBy = ISmartServiceConstants.DATABASE.RANKING.FIELD_SPEED + " DESC";
		try{

			cursor = dataAccessObject.getDB().query(
					ISmartServiceConstants.DATABASE.RANKING.TABLE_NAME,
					SELECTED_FIELDS,
					null, 
					null, null, null, orderBy);
			
			return getRecordsFromCursor(cursor);
			
		}catch(Exception e){
			throw new BackofficeDaoException("Erro ao executar query", e);
		} finally {
			if(cursor != null)
				cursor.close();
		}
	}
	
	public void deleteAllLines() throws BackofficeDBConnectionException, BackofficeDaoException {
		 dataAccessObject.getDB().delete(ISmartServiceConstants.DATABASE.RANKING.TABLE_NAME, null, null);
	}
	
	private AndroidContentValues createRecord(RankingAndroid rankingAndroid) {
		
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_ID, rankingAndroid.getXidRanking());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_NAME, rankingAndroid.getName());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_BRAND, rankingAndroid.getBrand());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_MODEL, rankingAndroid.getModel());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_LATITUDE, rankingAndroid.getLatitude());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_LONGITUDE, rankingAndroid.getLongitude());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_SPEED, rankingAndroid.getSpeed());
		contentValues.put(ISmartServiceConstants.DATABASE.RANKING.FIELD_DATE, rankingAndroid.getDate());
		
		return contentValues;
	}
	
	private List<RankingAndroid> getRecordsFromCursor(Cursor cursor) {
		
		List<RankingAndroid> result = new ArrayList<RankingAndroid>();
		
		while (cursor.moveToNext()) {
			
			RankingAndroid rankingAndroid = new RankingAndroid();
			
			rankingAndroid.setXidRanking(cursor.getLong(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_ID)));
			rankingAndroid.setName(cursor.getString(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_NAME)));
			rankingAndroid.setBrand(cursor.getString(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_BRAND)));
			rankingAndroid.setModel(cursor.getString(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_MODEL)));
			rankingAndroid.setLatitude(cursor.getDouble(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_LATITUDE)));
			rankingAndroid.setLongitude(cursor.getDouble(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_LONGITUDE)));
			rankingAndroid.setSpeed(cursor.getDouble(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_SPEED)));
			rankingAndroid.setDate(cursor.getLong(cursor.getColumnIndexOrThrow(ISmartServiceConstants.DATABASE.RANKING.FIELD_DATE)));
			
			result.add(rankingAndroid);
		}

		return result;
	}	
	
	private boolean validateEntityToPersist(RankingAndroid rankingAndroid) throws BackofficeIllegalArgumentDaoException {
		
		if (rankingAndroid.getName()      == null || 
				rankingAndroid.getLatitude()    == null || 
						rankingAndroid.getLongitude()   == null ||
								rankingAndroid.getDate() == null){
			throw new BackofficeIllegalArgumentDaoException("Posição invalida para atualização");			
		}
		return true;
	}	
	
}